Skip to content

Commit

Permalink
Dropped old-style symbols()
Browse files Browse the repository at this point in the history
Now symbols('xyz') means one symbol 'xyz', not three separate:

In [1]: symbols('xyz')
Out[1]: xyz

In [2]: symbols('x,y,z')
Out[2]: (x, y, z)

In [3]: symbols('x y z')
Out[3]: (x, y, z)

In [4]: symbols('x')
Out[4]: x

In [5]: symbols('x,')
Out[5]: (x,)

In [6]: symbols(('x', 'y', 'z'))
Out[6]: (x, y, z)

In [7]: symbols(['x', 'y', 'z'])
Out[7]: [x, y, z]

In [8]: symbols(['x', 'y', 'z:5'])
Out[8]: [x, y, (z₀, z₁, z₂, z₃, z₄)]

In [9]: symbols('x,y,z:5')
Out[9]: (x, y, z₀, z₁, z₂, z₃, z₄)

In [10]: symbols('x', seq=True)
Out[10]: (x,)

In [11]: symbols('f', cls=Function)
Out[11]: f

In [12]: type(_)
Out[12]: <class 'sympy.core.function.UndefinedFunction'>

ok
  • Loading branch information
mattpap authored and rlamy committed Apr 21, 2011
1 parent 79d41d0 commit f6452a8
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 115 deletions.
224 changes: 129 additions & 95 deletions sympy/core/symbol.py
Expand Up @@ -16,7 +16,7 @@ class Symbol(AtomicExpr, Boolean):
You can override the default assumptions in the constructor::
>>> from sympy import symbols
>>> A,B = symbols('AB', commutative = False)
>>> A,B = symbols('A,B', commutative = False)
>>> bool(A*B != B*A)
True
>>> bool(A*B*2 == 2*A*B) == True # multiplication by scalars is commutative
Expand Down Expand Up @@ -205,51 +205,78 @@ class Pure(Expr):
_re_var_range = re.compile(r"^(.*?)(\d*):(\d+)$")
_re_var_split = re.compile(r"\s|,")

def symbols(*names, **kwargs):
def symbols(names, **args):
"""
Return a list of symbols with names taken from 'names'
argument, which can be a string, then each character
forms a separate symbol, or a sequence of strings.
Transform strings into instances of :class:`Symbol` class.
>>> from sympy import symbols
>>> x, y, z = symbols('xyz')
:func:`symbols` function returns a sequence of symbols with names taken
from ``names`` argument, which can be a comma or whitespace delimited
string, or a sequence of strings::
Please note that this syntax is deprecated and will be dropped in a
future version of sympy. Use comma or whitespace separated characters
instead. Currently the old behavior is standard, this can be changed
using the 'each_char' keyword:
>>> from sympy import symbols, Function
>>> symbols('xyz', each_char=False)
xyz
>>> x, y, z = symbols('x,y,z')
>>> a, b, c = symbols('a b c')
All newly created symbols have assumptions set accordingly
to 'kwargs'. Main intention behind this function is to
simplify and shorten examples code in doc-strings.
The type of output is dependent on the properties of input arguments::
>>> a = symbols('a', integer=True)
>>> a.is_integer
True
>>> xx, yy, zz = symbols('xx', 'yy', 'zz', real=True)
>>> xx.is_real and yy.is_real and zz.is_real
True
>>> x = symbols('x')
>>> (x,) = symbols('x,')
>>> symbols(('a', 'b', 'c'))
(a, b, c)
>>> symbols(['a', 'b', 'c'])
[a, b, c]
>>> symbols(set(['a', 'b', 'c']))
set([a, b, c])
If an iterable container is needed set ``seq`` argument to ``True``::
>>> symbols('x', seq=True)
(x,)
To cut on typing, range syntax is supported co create indexed symbols::
>>> symbols('x:10')
(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
>>> symbols('x5:10')
(x5, x6, x7, x8, x9)
>>> symbols('x5:10,y:5')
(x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
>>> symbols(('x5:10', 'y:5'))
((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))
All newly created symbols have assumptions set accordingly to ``args``::
>>> a = symbols('a', integer=True)
>>> a.is_integer
True
>>> x, y, z = symbols('x,y,z', real=True)
>>> x.is_real and y.is_real and z.is_real
True
Despite its name, :func:`symbols` can create symbol--like objects of
other type, for example instances of Function or Wild classes. To
achieve this, set ``cls`` keyword argument to the desired type::
>>> symbols('f,g,h', cls=Function)
(f, g, h)
>>> type(_[0])
<class 'sympy.core.function.UndefinedFunction'>
"""
func = Symbol
# when polys12 is in place remove from here...
if 'cls' in kwargs and kwargs.pop('cls') is Dummy:
func = Dummy
# ... to here when polys12 is in place
# use new behavior if space or comma in string
if not 'each_char' in kwargs and len(names) == 1 and \
isinstance(names[0], str) and (' ' in names[0] or ',' in names[0]):
kwargs['each_char'] = False
if not kwargs.pop("each_char", True):
names = names[0]

if not isinstance(names, list):
names = _re_var_split.split(names)

result = []
result = []

if isinstance(names, basestring):
names = _re_var_split.split(names)

cls = args.pop('cls', Symbol)
seq = args.pop('seq', False)

for name in names:
if not name:
Expand All @@ -266,72 +293,79 @@ def symbols(*names, **kwargs):
start = int(start)

for i in xrange(start, int(end)):
symbol = func("%s%i" % (name, i), **kwargs)
symbol = cls("%s%i" % (name, i), **args)
result.append(symbol)

seq = True
else:
symbol = func(name, **kwargs)
symbol = cls(name, **args)
result.append(symbol)

result = tuple(result)

if len(result) <= 1:
if not result: # var('')
result = None
else: # var('x')
result = result[0]
if not seq and len(result) <= 1:
if not result:
return None
elif names[-1]:
return result[0]

return result
return tuple(result)
else:
# this is the old, deprecated behavior:
if len(names) == 1:
result = [ func(name, **kwargs) for name in names[0] ]
else:
result = [ func(name, **kwargs) for name in names ]
if len(result) == 1:
return result[0]
else:
return result
for name in names:
syms = symbols(name, **args)

if syms is not None:
result.append(syms)

def var(*names, **kwargs):
return type(names)(result)

def var(names, **args):
"""
Create symbols and inject them into global namespace.
This calls symbols() with the same arguments and puts the results into
global namespace. Unlike symbols(), it uses each_char=False by default
for compatibility reasons.
NOTE: The new variable is both returned and automatically injected into
the parent's *global* namespace. It's recommended not to use "var" in
library code, it is better to use symbols() instead.
>>> from sympy import var
>>> var('m')
m
>>> var('n xx yy zz')
(n, xx, yy, zz)
>>> n
n
>>> var('x y', real=True)
(x, y)
>>> x.is_real and y.is_real
True
Create symbols and inject them into the global namespace.
This calls :func:`symbols` with the same arguments and puts the results
into the *global* namespace. It's recommended not to use :func:`var` in
library code, where :func:`symbols` has to be used::
>>> from sympy import var
>>> var('x')
x
>>> x
x
>>> var('a,ab,abc')
(a, ab, abc)
>>> abc
abc
>>> var('x,y', real=True)
(x, y)
>>> x.is_real and y.is_real
True
See :func:`symbol` documentation for more details on what kinds of
arguments can be passed to :func:`var`.
"""
import inspect
frame = inspect.currentframe().f_back
def traverse(symbols, frame):
"""Recursively inject symbols to the global namespace. """
for symbol in symbols:
if isinstance(symbol, Basic):
frame.f_globals[symbol.name] = symbol
else:
traverse(symbol, frame)

from inspect import currentframe
frame = currentframe().f_back

try:
kwargs['each_char'] = False
s = symbols(*names, **kwargs)
if s is None:
return s
if isinstance(s, Symbol):
s_list = [s]
else:
s_list = s
for t in s_list:
frame.f_globals[t.name] = t
return s
syms = symbols(names, **args)

if syms is not None:
if isinstance(syms, Basic):
frame.f_globals[syms.name] = syms
else:
traverse(syms, frame)
finally:
# we should explicitly break cyclic dependencies as stated in inspect
# doc
del frame
del frame # break cyclic dependencies as stated in inspect docs

return syms
85 changes: 66 additions & 19 deletions sympy/core/tests/test_symbol.py
Expand Up @@ -144,25 +144,72 @@ def test_Pure():
assert (S.Pure != I) == True

def test_symbols():
x, y, z = Symbol('x'), Symbol('y'), Symbol('z')
assert symbols('x') == Symbol('x')
assert symbols('xyz') == [x, y, z]
assert symbols('x y z') == symbols('x,y,z') == (x, y, z)
assert symbols('xyz', each_char=False) == Symbol('xyz')
x, y = symbols('x y', each_char=False, real=True)
assert x.is_real and y.is_real

assert symbols('x0:0', each_char=False) is None
assert symbols('x0:1', each_char=False) == Symbol('x0')
assert symbols('x0:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2'))

assert symbols('x:0', each_char=False) is None
assert symbols('x:1', each_char=False) == Symbol('x0')
assert symbols('x:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2'))

assert symbols('x1:1', each_char=False) is None
assert symbols('x1:2', each_char=False) == Symbol('x1')
assert symbols('x1:3', each_char=False) == (Symbol('x1'), Symbol('x2'))
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')

assert symbols('') is None

assert symbols('x') == x
assert symbols('x,') == (x,)
assert symbols('x ') == (x,)

assert symbols('x,y,z') == (x, y, z)
assert symbols('x y z') == (x, y, z)

assert symbols('x,y,z,') == (x, y, z)
assert symbols('x y z ') == (x, y, z)

xyz = Symbol('xyz')
abc = Symbol('abc')

assert symbols('xyz') == xyz
assert symbols('xyz,') == (xyz,)
assert symbols('xyz,abc') == (xyz, abc)

assert symbols(('xyz',)) == (xyz,)
assert symbols(('xyz,',)) == ((xyz,),)
assert symbols(('x,y,z,',)) == ((x, y, z),)
assert symbols(('xyz', 'abc')) == (xyz, abc)
assert symbols(('xyz,abc',)) == ((xyz, abc),)
assert symbols(('xyz,abc', 'x,y,z')) == ((xyz, abc), (x, y, z))

assert symbols(('x', 'y', 'z')) == (x, y, z)
assert symbols(['x', 'y', 'z']) == [x, y, z]
assert symbols(set(['x', 'y', 'z'])) == set([x, y, z])

assert symbols('x,,y,,z') == (x, y, z)
assert symbols(('x', '', 'y', '', 'z')) == (x, y, z)

a, b = symbols('x,y', real=True)

assert a.is_real and b.is_real

x0 = Symbol('x0')
x1 = Symbol('x1')
x2 = Symbol('x2')

y0 = Symbol('y0')
y1 = Symbol('y1')

assert symbols('x0:0') == ()
assert symbols('x0:1') == (x0,)
assert symbols('x0:2') == (x0, x1)
assert symbols('x0:3') == (x0, x1, x2)

assert symbols('x:0') == ()
assert symbols('x:1') == (x0,)
assert symbols('x:2') == (x0, x1)
assert symbols('x:3') == (x0, x1, x2)

assert symbols('x1:1') == ()
assert symbols('x1:2') == (x1,)
assert symbols('x1:3') == (x1, x2)

assert symbols('x1:3,x,y,z') == (x1, x2, x, y, z)

assert symbols('x:3,y:2') == (x0, x1, x2, y0, y1)
assert symbols(('x:3', 'y:2')) == ((x0, x1, x2), (y0, y1))

def test_call():
f = Symbol('f')
Expand Down
2 changes: 1 addition & 1 deletion sympy/core/tests/test_var.py
Expand Up @@ -32,7 +32,7 @@ def test_var():
assert fg == Symbol('fg')

# check return value
assert v == (d, e, fg)
assert v == [d, e, fg]

# see if var() really injects into global namespace
raises(NameError, "z1")
Expand Down

0 comments on commit f6452a8

Please sign in to comment.