@@ -58,15 +58,17 @@ def _process_keys(left, right):
58
58
59
59
Parameters
60
60
----------
61
- left, right : Cycler or None
61
+ left, right : iterable of dictionaries or None
62
62
The cyclers to be composed
63
63
Returns
64
64
-------
65
65
keys : set
66
66
The keys in the composition of the two cyclers
67
67
"""
68
- l_key = left .keys if left is not None else set ()
69
- r_key = right .keys if right is not None else set ()
68
+ l_peek = next (iter (left )) if left is not None else {}
69
+ r_peek = next (iter (right )) if right is not None else {}
70
+ l_key = set (l_peek .keys ())
71
+ r_key = set (r_peek .keys ())
70
72
if l_key & r_key :
71
73
raise ValueError ("Can not compose overlapping cycles" )
72
74
return l_key | r_key
@@ -112,9 +114,21 @@ def __init__(self, left, right=None, op=None):
112
114
113
115
Do not use this directly, use `cycler` function instead.
114
116
"""
115
- self ._keys = _process_keys (left , right )
116
- self ._left = copy .deepcopy (left )
117
- self ._right = copy .deepcopy (right )
117
+ if isinstance (left , Cycler ):
118
+ self ._left = Cycler (left ._left , left ._right , left ._op )
119
+ elif left is not None :
120
+ self ._left = list (left )
121
+ else :
122
+ self ._left = None
123
+
124
+ if isinstance (right , Cycler ):
125
+ self ._right = Cycler (right ._left , right ._right , right ._op )
126
+ elif right is not None :
127
+ self ._right = list (right )
128
+ else :
129
+ self ._right = None
130
+
131
+ self ._keys = _process_keys (self ._left , self ._right )
118
132
self ._op = op
119
133
120
134
@property
@@ -228,11 +242,14 @@ def __iadd__(self, other):
228
242
other : Cycler
229
243
The second Cycler
230
244
"""
231
- old_self = copy .deepcopy (self )
245
+ if not isinstance (other , Cycler ):
246
+ raise TypeError ("Cannot += with a non-Cycler object" )
247
+ # True shallow copy of self is fine since this is in-place
248
+ old_self = copy .copy (self )
232
249
self ._keys = _process_keys (old_self , other )
233
250
self ._left = old_self
234
251
self ._op = zip
235
- self ._right = copy . deepcopy (other )
252
+ self ._right = Cycler (other . _left , other . _right , other . _op )
236
253
return self
237
254
238
255
def __imul__ (self , other ):
@@ -244,12 +261,14 @@ def __imul__(self, other):
244
261
other : Cycler
245
262
The second Cycler
246
263
"""
247
-
248
- old_self = copy .deepcopy (self )
264
+ if not isinstance (other , Cycler ):
265
+ raise TypeError ("Cannot *= with a non-Cycler object" )
266
+ # True shallow copy of self is fine since this is in-place
267
+ old_self = copy .copy (self )
249
268
self ._keys = _process_keys (old_self , other )
250
269
self ._left = old_self
251
270
self ._op = product
252
- self ._right = copy . deepcopy (other )
271
+ self ._right = Cycler (other . _left , other . _right , other . _op )
253
272
return self
254
273
255
274
def __eq__ (self , other ):
@@ -354,7 +373,7 @@ def cycler(*args, **kwargs):
354
373
Parameters
355
374
----------
356
375
arg : Cycler
357
- Copy constructor for Cycler.
376
+ Copy constructor for Cycler (does a shallow copy of iterables) .
358
377
359
378
label : name
360
379
The property key. In the 2-arg form of the function,
@@ -363,6 +382,8 @@ def cycler(*args, **kwargs):
363
382
364
383
itr : iterable
365
384
Finite length iterable of the property values.
385
+ Can be a single-property `Cycler` that would
386
+ be like a key change, but as a shallow copy.
366
387
367
388
Returns
368
389
-------
@@ -378,7 +399,7 @@ def cycler(*args, **kwargs):
378
399
if not isinstance (args [0 ], Cycler ):
379
400
raise TypeError ("If only one positional argument given, it must "
380
401
" be a Cycler instance." )
381
- return copy . deepcopy (args [0 ])
402
+ return Cycler (args [0 ])
382
403
elif len (args ) == 2 :
383
404
return _cycler (* args )
384
405
elif len (args ) > 2 :
@@ -415,10 +436,9 @@ def _cycler(label, itr):
415
436
msg = "Can not create Cycler from a multi-property Cycler"
416
437
raise ValueError (msg )
417
438
418
- if label in keys :
419
- return copy .deepcopy (itr )
420
- else :
421
- lab = keys .pop ()
422
- itr = list (v [lab ] for v in itr )
439
+ lab = keys .pop ()
440
+ # Doesn't need to be a new list because
441
+ # _from_iter() will be creating that new list anyway.
442
+ itr = (v [lab ] for v in itr )
423
443
424
444
return Cycler ._from_iter (label , itr )
0 commit comments