python thousands separator formatting with different character without using locale - python

I am looking to format thousands with an apostrophe (but could be something else) without using locale or a replace method.
The comma that is used by default in the string formatting must be defined somewhere in the Python source code but I can't find where. Is it possible to access it and change it once so that all formatting in the same session uses the new character?
To be clear (edit after #Matiss comment), I do not want to change the formatting syntax. It should stay as f"{value:,}". However, instead of inserting commas, I would like to insert something else.
Hopefully the comma is declared as a constant somewhere in Python source code (for example string._THOUSANDS_SEPARATOR), and just re-assigning it to soemthing else will do the trick.
I can not find that constant definition.
For example, one of the ways to do it now is:
>>> val = 123456
>>> print(f"{val:,}".replace(",", "'"))
123'456
The replace method is cumbersome and has to be repeated every time.
I also want to avoid the locale environment.
If the comma , is defined as a constant somewhere in Python source code, say for example in a module called python_formatting_constants, and the name of the constant was for example THOUSANDS_SEPARATOR, one could do:
>>> from python_formatting_constants import THOUSANDS_SEPARATOR
>>> THOUSANDS_SEPARATOR = "'"
>>> print(f"{val:,}") # the "," in the formatting string stays the same
123'456
>>> # but the formatted string uses the apostrophe instead of the comma

If you want to do the changes from the core of python, then you might need help from python language developers. But You can create your own format specs by creating your own class and override any provided format specs does not work for you.
class MyInt(int):
def __new__(cls, number):
return super(MyInt, cls).__new__(cls, number)
def __init__(self, value):
self.value = value
def __format__(self, format_spec):
if format_spec == ",":
return format(self.value, ",").replace(",", "'")
return format(self.value, format_spec)
Here I have created my own class which is a subclass of int and I have overloaded the __format__ built-in method of int according to your need.
Example:
# Input
test_value = TestClass(1000)
"{:,}".format(test_value) # alternative: f"{test_value:,}"
# Output
"1'000"
It is just a dummy example, You can do more deep dive into format_spec argument of __format__ method to have your own and replace any existing identifier with your own.
My suggestion will be, it will be quite easier to create your own format_spec than waiting to get some help from core python development team.
Few caveats:
If you are planning to do some add, subtract ... etc with integer and your new class, then you also have to overload all those functions for example __add__, __sub__ because any numeric operation will return pure int but not MyInt which has its own formatting.
Example:
# input
another_value = test_value + 2500
"{:,}".format(another_value)
# output
'3,500'
As you can see, the return value of + is a int but not MyInt so it has used , in the output instead. So you have to do all numeric operation beforehand and then wrap the final numeric result with the MyInt for just to have proper formatting.
More details about the format specs here.

Related

How do I specify literally a specific type (like str (not instance of str)) in Python with type hinting?

Is there a way I can specify a variable should be literally a specific type in Python?
I know that it is possible to specify a variable should a specific type or subtype, but how can I specify only that type?
var: str # instance of string
var: type[str] # subtype or type string
var: (literally str class) # part in question
An example of when this functionality may be necessary pertains to Union types. For example, what if I want the argument passed to a specific parameter of a function or the return type of a function to be literally the type int or str?
def example1(arg: (Literally) int | (Literally) str):
...
def example2(arg) -> (Literally) int | (Literally) str:
...
If you want to specify a type for your variable you can follow this practice,
before putting any values in your variable, define the variable like this:
string:
x = ''
list:
x = []
Dictionary:
x = {}
and so on ...
TL;DR: You don't.
That is not how types work in general. It's like asking "how can I check if something is just a bear, but not a polar bear, grizzly bear, or any other subtype of bear?" What does that even mean?
If something can be subtyped, there is no way to do what you are asking.
Note that I am talking about static type checking here, not about runtime logic. Of course you can do this:
assert type(x) is str
That will ensure that x is of the str class and not of a subclass, but there are good reasons, why that is usually discouraged in favor of this:
assert isinstance(x, str)
That has almost nothing to do with type annotations of variables though.
By default, a type can have any number of descendant types. If you want to have a custom type, which is final, i.e. subtypes shall not exist, you can make use of PEP 591:
from typing import final
#final
class MyStr(str):
pass
if __name__ == '__main__':
x: MyStr
x = MyStr("abc")
The relevant thing for the type checker here is that MyStr is final, which means that it will give you an error the moment you try to subclass MyStr without even concerning itself with whether you assign a value of that subclass to x later on. Taking mypy for example, if you do this:
from typing import final
#final
class MyStr(str):
pass
class OtherStr(MyStr): # this is where the error occurs
pass
if __name__ == '__main__':
x: MyStr
x = OtherStr("abc") # irrelevant at this point
It will not complain about the last line at all. Instead it will only say:
error: Cannot inherit from final class "MyStr" [misc]
In other words, the moment you try and create a subclass, the rest of the things you do with that class no longer matter because they are by definition invalid.
If you really want to, you can of course shadow str, but this will come with a bunch of caveats:
from builtins import str as built_in_str
from typing import final
#final
class str(built_in_str):
pass
if __name__ == '__main__':
x: str
x = str("abc")
I think this is a very bad idea. One reason is that you won't be able to just use a string literal "abc" to assign to x because that gives you a builtin.str object. But I think you can imagine whole lot of other problems.
Hope this makes sense.

How to assign data type to a parameter and if that data type is not same as i assigned raise an error?

Alright, so i was coding when i stumbled upon a problem:
def myFunction(string):
print(string + "test")
Now, when i put a string, it runs perfectly fine. But, when i put in an int:
myFunction(str(1)):
It still works? Now, i know i put a str() function to the "1" value. But, if i wanted to have a function that takes in a parameter with the data type string, and type an integer value to that parameter, it still works. How can i do it?
One option is to use f-strings, which allows myFunction to concatenate a type other than a string, with a string:
def myFunction(o: object):
print(f'{o}test')
Or, even better yet:
def myFunction(o: object):
print(o, 'test', sep='')
Then the desired call should work without needing to wrap the value in str() explicitly:
>>> myFunction(1)
1test
If you prefer to be more explicit, I'd suggest changing it like below; what this does is call str(o) internally, only it looks a bit nicer.
def myFunction(o: object):
print(f'{o!s}test')

How to stack multiple calls? [duplicate]

I'm trying to create a function that chains results from multiple arguments.
def hi(string):
print(string)<p>
return hi
Calling hi("Hello")("World") works and becomes Hello \n World as expected.
the problem is when I want to append the result as a single string, but
return string + hi produces an error since hi is a function.
I've tried using __str__ and __repr__ to change how hi behaves when it has not input. But this only creates a different problem elsewhere.
hi("Hello")("World") = "Hello"("World") -> Naturally produces an error.
I understand why the program cannot solve it, but I cannot find a solution to it.
You're running into difficulty here because the result of each call to the function must itself be callable (so you can chain another function call), while at the same time also being a legitimate string (in case you don't chain another function call and just use the return value as-is).
Fortunately Python has you covered: any type can be made to be callable like a function by defining a __call__ method on it. Built-in types like str don't have such a method, but you can define a subclass of str that does.
class hi(str):
def __call__(self, string):
return hi(self + '\n' + string)
This isn't very pretty and is sorta fragile (i.e. you will end up with regular str objects when you do almost any operation with your special string, unless you override all methods of str to return hi instances instead) and so isn't considered very Pythonic.
In this particular case it wouldn't much matter if you end up with regular str instances when you start using the result, because at that point you're done chaining function calls, or should be in any sane world. However, this is often an issue in the general case where you're adding functionality to a built-in type via subclassing.
To a first approximation, the question in your title can be answered similarly:
class add(int): # could also subclass float
def __call__(self, value):
return add(self + value)
To really do add() right, though, you want to be able to return a callable subclass of the result type, whatever type it may be; it could be something besides int or float. Rather than trying to catalog these types and manually write the necessary subclasses, we can dynamically create them based on the result type. Here's a quick-and-dirty version:
class AddMixIn(object):
def __call__(self, value):
return add(self + value)
def add(value, _classes={}):
t = type(value)
if t not in _classes:
_classes[t] = type("add_" + t.__name__, (t, AddMixIn), {})
return _classes[t](value)
Happily, this implementation works fine for strings, since they can be concatenated using +.
Once you've started down this path, you'll probably want to do this for other operations too. It's a drag copying and pasting basically the same code for every operation, so let's write a function that writes the functions for you! Just specify a function that actually does the work, i.e., takes two values and does something to them, and it gives you back a function that does all the class munging for you. You can specify the operation with a lambda (anonymous function) or a predefined function, such as one from the operator module. Since it's a function that takes a function and returns a function (well, a callable object), it can also be used as a decorator!
def chainable(operation):
class CallMixIn(object):
def __call__(self, value):
return do(operation(self, value))
def do(value, _classes={}):
t = type(value)
if t not in _classes:
_classes[t] = type(t.__name__, (t, CallMixIn), {})
return _classes[t](value)
return do
add = chainable(lambda a, b: a + b)
# or...
import operator
add = chainable(operator.add)
# or as a decorator...
#chainable
def add(a, b): return a + b
In the end it's still not very pretty and is still sorta fragile and still wouldn't be considered very Pythonic.
If you're willing to use an additional (empty) call to signal the end of the chain, things get a lot simpler, because you just need to return functions until you're called with no argument:
def add(x):
return lambda y=None: x if y is None else add(x+y)
You call it like this:
add(3)(4)(5)() # 12
You are getting into some deep, Haskell-style, type-theoretical issues by having hi return a reference to itself. Instead, just accept multiple arguments and concatenate them in the function.
def hi(*args):
return "\n".join(args)
Some example usages:
print(hi("Hello", "World"))
print("Hello\n" + hi("World"))

Python PEP3101: Why the field_spec is not passed to the __format__ function?

PEP 3101 specifies Advanced String Formatting. Among other things, it defines a specification of a new syntax for format strings (eg. {:.2f}) and how custom types can control their own formatting. This is done by implementing:
def __format__(value, format_spec):
# Your code here
The string formatting code can include a conversion flag. For example: "{0!r:20}".format("Hello"), where !r means convert the the value to a string using repr(). However, __format__ only gets the value after the colon : (i.e. the format_spec). I would like to know is the reason (i.e. the design decision, not the code) why? I think that providing everything after the the ! will be more flexible.
The part before the colon is only used in string formatting, and is a templating function, not about formatting the actual values themselves.
The part after the colon is handled separately, and can also be specified using the format() function:
>>> format(234, '02x')
'ea'
formats the number as lower-cased zero-padded hexadecimal of minimal 2 characters. It is this functionality that .__format__() lets you hook into; this is the business end of formatting the value.
The part before the colon specifies the field_name, how the string formatter retrieves a value to format. When formatting the value, it shouldn't matter at all how the field was determined. The field_name is only useful to locate the value on which to call .__format__(), and to specify an alternate conversion method (!r or !s) for that value.
Note that by using !r the .__format__() method is ignored and .__repr__() is used instead! The same applies to !s and .__str__():
>>> class Foo(object):
... def __repr__(self): return '<Foo repr>'
... def __str__(self): return 'Foo as string'
... def __format__(self, spec): return 'Formatting Foo as {}'.format(spec)
...
>>> '{:02x}'.format(Foo())
'Formatting Foo as 02x'
>>> '{!s}'.format(Foo())
'Foo as string'
>>> '{!r}'.format(Foo())
'<Foo repr>'

how to declare variable type, C style in python

I'm a programming student and my teacher is starting with C to teach us the programming paradigms, he said it's ok if I deliver my homework in python (it's easier and faster for the homeworks). And I would like to have my code to be as close as possible as in plain C.
Question is:
How do I declare data types for variables in python like you do in C. ex:
int X,Y,Z;
I know I can do this in python:
x = 0
y = 0
z = 0
But that seems a lot of work and it misses the point of python being easier/faster than C.
So, whats the shortest way to do this?
P.S. I know you don't have to declare the data type in python most of the time, but still I would like to do it so my code looks as much possible like classmates'.
Starting with Python 3.6, you can declare types of variables and functions, like this :
explicit_number: type
or for a function
def function(explicit_number: type) -> type:
pass
This example from this post: How to Use Static Type Checking in Python 3.6 is more explicit
from typing import Dict
def get_first_name(full_name: str) -> str:
return full_name.split(" ")[0]
fallback_name: Dict[str, str] = {
"first_name": "UserFirstName",
"last_name": "UserLastName"
}
raw_name: str = input("Please enter your name: ")
first_name: str = get_first_name(raw_name)
# If the user didn't type anything in, use the fallback name
if not first_name:
first_name = get_first_name(fallback_name)
print(f"Hi, {first_name}!")
See the docs for the typing module
Edit: Python 3.5 introduced type hints which introduced a way to specify the type of a variable. This answer was written before this feature became available.
There is no way to declare variables in Python, since neither "declaration" nor "variables" in the C sense exist. This will bind the three names to the same object:
x = y = z = 0
Simply said: Typing in python is useful for hinting only.
x: int = 0
y: int = 0
z: int = 0
Python isn't necessarily easier/faster than C, though it's possible that it's simpler ;)
To clarify another statement you made, "you don't have to declare the data type" - it should be restated that you can't declare the data type. When you assign a value to a variable, the type of the value becomes the type of the variable. It's a subtle difference, but different nonetheless.
I'm surprised no one has pointed out that you actually can do this:
decimalTwenty = float(20)
In a lot of cases it is meaningless to type a variable, as it can be retyped at any time. However in the above example it could be useful. There are other type functions like this such as: int(), long(), float() and complex()
But strong types and variable definitions are actually there to make development easier. If you haven't thought these things through in advance you're not designing and developing code but merely hacking.
Loose types simply shift the complexity from "design/hack" time to run time.
Everything in Python is an object, and that includes classes, class instances, code in functions, libraries of functions called modules, as well as data values like integers, floating-point numbers, strings, or containers like lists and dictionaries. It even includes namespaces which are dictionary-like (or mapping) containers which are used to keep track of the associations between identifier names (character string objects) and to the objects which currently exist. An object can even have multiple names if two or more identifiers become associated with the same object.
Associating an identifier with an object is called "binding a name to the object". That's the closest thing to a variable declaration there is in Python. Names can be associated with different objects at different times, so it makes no sense to declare what type of data you're going to attach one to -- you just do it. Often it's done in one line or block of code which specifies both the name and a definition of the object's value causing it to be created, like <variable> = 0 or a function starting with a def <funcname>.
How this helps.
I use data types to assert unique values in python 2 and 3. Otherwise I cant make them work like a str or int types. However if you need to check a value that can have any type except a specific one, then they are mighty useful and make code read better.
Inherit object will make a type in python.
class unset(object):
pass
>>> print type(unset)
<type 'type'>
Example Use: you might want to conditionally filter or print a value using a condition or a function handler so using a type as a default value will be useful.
from __future__ import print_function # make python2/3 compatible
class unset(object):
pass
def some_func(a,b, show_if=unset):
result = a + b
## just return it
if show_if is unset:
return result
## handle show_if to conditionally output something
if hasattr(show_if,'__call__'):
if show_if(result):
print( "show_if %s = %s" % ( show_if.__name__ , result ))
elif show_if:
print(show_if, " condition met ", result)
return result
print("Are > 5)")
for i in range(10):
result = some_func(i,2, show_if= i>5 )
def is_even(val):
return not val % 2
print("Are even")
for i in range(10):
result = some_func(i,2, show_if= is_even )
Output
Are > 5)
True condition met 8
True condition met 9
True condition met 10
True condition met 11
Are even
show_if is_even = 2
show_if is_even = 4
show_if is_even = 6
show_if is_even = 8
show_if is_even = 10
if show_if=unset is perfect use case for this because its safer and reads well. I have also used them in enums which are not really a thing in python.

Categories

Resources